﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Data.Linq;
using System.Linq;
using System.Reflection;
using System.Runtime.Serialization;
using System.Text;
using Dycox.Workflows.Data;

namespace Dycox.Workflows
{
    internal static class LinqToSqlBinarySerialization
    {
        public static void GetObjectData(object entity, SerializationInfo info, StreamingContext context)
        {
            FieldInfo[] fields = entity.GetType().GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.DeclaredOnly);

            foreach (FieldInfo fld in fields)
            {
                if (!fld.IsLiteral && Attribute.GetCustomAttribute(fld, typeof(NonSerializedAttribute)) == null)
                {
                    Type type = fld.FieldType;
                    object value = fld.GetValue(entity);
                    if (value != null)
                    {
                        if (!type.IsSerializable)
                        {
                            Type gendef = type.GetGenericTypeDefinition();

                            if (gendef == typeof(EntityRef<>))
                            {
                                value = type.GetProperty("Entity").GetValue(value, null);
                                if (value != null)
                                    info.AddValue(fld.Name, value);
                            }
                            else if (gendef == typeof(EntitySet<>))
                            {
                                ICollection coll = (ICollection)value;
                                Array array = Array.CreateInstance(type.GetGenericArguments()[0], coll.Count);
                                coll.CopyTo(array, 0);
                                info.AddValue(fld.Name, array);
                            }
                            else
                                throw new NotSupportedException("Unexpected non-serializable type: " + type.AssemblyQualifiedName);
                        }
                        else
                            info.AddValue(fld.Name, value);
                    }
                }
            }
        }
    }
}
